/*

Miranda IM: the free IM client for Microsoft* Windows*

Copyright 2000-2007 Miranda ICQ/IM project, 
all portions of this codebase are copyrighted to the people 
listed in contributors.txt.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
aLONG with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

/**
 * Local Includes:
 **/
#include "commonheaders.h"

#include <Commdlg.h>
/**
 * Miranda Includes:
 **/
#include "m_clui.h"
#include "m_skin.h"

/**
 * name:   MsgBoxProc
 * desc:   message procedure for my nice looking message box
 * param:   hDlg   - window handle
 *         uMsg   - message to handle
 *         wParam   - message specific parameter
 *         lParam   - message specific parameter
 *
 * return:   TRUE, FALSE, IDOK, IDYES, IDALL, IDNO or IDCANCEL
 **/
static INT CALLBACK MsgBoxProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   static INT   retOk = IDOK,
            retCancel = IDCANCEL,
            retAll = IDALL;

   switch(uMsg) {
      case WM_INITDIALOG:
      {
         LPMSGBOX pmb = (LPMSGBOX)lParam;
         INT icoWidth = 0;

         if(!PtrIsValid(pmb))
            return FALSE;

         // set bold font for name in description area
         {
            LOGFONT lf;
            HFONT hNormalFont = (HFONT)SendDlgItemMessage(hDlg, TXT_NAME, WM_GETFONT, 0, 0);
            GetObject(hNormalFont, sizeof(lf), &lf);
            lf.lfWeight = FW_BOLD;
            hNormalFont = CreateFontIndirect(&lf);
            SendDlgItemMessage(hDlg, TXT_NAME, WM_SETFONT, (WPARAM)hNormalFont, 0);
         }
         // set infobar's logo icon
         SendDlgItemMessage(hDlg, ICO_DLGLOGO, STM_SETIMAGE, IMAGE_ICON, (LPARAM)((pmb->hiLogo) ? pmb->hiLogo : LoadIcon(ghInst, MAKEINTRESOURCE(IDI_MAIN))));

         // draw the desired status icon
         switch(pmb->uType & 0x000000F0) {
            case MB_ICON_ERROR:
               SendDlgItemMessage(hDlg, ICO_MSGDLG, STM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIcon(NULL, IDI_ERROR));
               break;
            case MB_ICON_QUESTION:
               SendDlgItemMessage(hDlg, ICO_MSGDLG, STM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIcon(NULL, IDI_QUESTION));
               break;
            case MB_ICON_WARNING:
               SendDlgItemMessage(hDlg, ICO_MSGDLG, STM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIcon(NULL, IDI_WARNING));
               break;
            case MB_ICON_INFO:
               SendDlgItemMessage(hDlg, ICO_MSGDLG, STM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIcon(NULL, IDI_INFORMATION));
               break;
            case MB_ICON_OTHER:
               SendDlgItemMessage(hDlg, ICO_MSGDLG, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pmb->hiMsg);
               break;
            case MB_ICON_NONE:
            default:
            {
               RECT ws;
               GetWindowRect(GetDlgItem(hDlg, ICO_MSGDLG), &ws);
               icoWidth = ws.right - ws.left;
               ShowWindow(GetDlgItem(hDlg, ICO_MSGDLG), SW_HIDE);
               break;
            }
         }
         // resize the messagebox and reorganize the buttons
         {
            RECT   rcDlg;
            HDC      hDC;
            POINT   mpt = {0,0};
            RECT   ws = {0,0,0,0};
            INT      txtWidth,
                  txtHeight,
                  numLines,
                  needX, needY;

            // calc max width of text & number of lines
            if((hDC = GetDC(hDlg))) {
               SIZE   ts;

               SelectObject(hDC, (HFONT)SendDlgItemMessage(hDlg, TXT_MESSAGE, WM_GETFONT, 0, 0));
               
               if((pmb->uType & 0xF0000000) == MB_UNICODE) {
                  LPWSTR   h, rowStart;
   
                  for(rowStart = h = pmb->pwszMsg, txtWidth = 0, numLines = 1; h; h++) {
                     if(*h == '\n' || *h == '\0') {
                        GetTextExtentPoint32W(hDC, rowStart, h - rowStart, &ts);
                        if(ts.cx > txtWidth)
                           txtWidth = ts.cx;
                        if(*h == '\0') break;
                        rowStart = h + 1;
                        numLines++;
                     }
                  }
               }
               else {
                  LPSTR h, rowStart;
   
                  for(rowStart = h = pmb->pszMsg, txtWidth = 0, numLines = 1; h; h++) {
                     if(*h == '\n' || *h == '\0') {
                        GetTextExtentPoint32A(hDC, rowStart, h - rowStart, &ts);
                        if(ts.cx > txtWidth)
                           txtWidth = ts.cx;

                        if(*h == '\0') break;
                        rowStart = h + 1;
                        numLines++;
                     }
                  }
               }
               txtHeight = numLines * ts.cy;
               ReleaseDC(hDlg, hDC);
            }

            // calc new dialog size
            GetWindowRect(hDlg, &rcDlg);
            GetWindowRect(GetDlgItem(hDlg, TXT_MESSAGE), &ws);
            needX = max(0, txtWidth - (ws.right - ws.left) - icoWidth);
            needY = max(0, txtHeight - (ws.bottom - ws.top));
            rcDlg.left -= needX/2; rcDlg.right += needX/2;
            rcDlg.top -= needY/2; rcDlg.bottom += needY/2;
            // risize dialog window
            MoveWindow(hDlg, 
                  rcDlg.left, rcDlg.top, 
                  rcDlg.right - rcDlg.left, rcDlg.bottom - rcDlg.top,
                  FALSE);
            ClientToScreen(hDlg, &mpt);
            // resize text control
            GetWindowRect(GetDlgItem(hDlg, TXT_MESSAGE), &ws);
            OffsetRect(&ws, -mpt.x, -mpt.y);
            MoveWindow(GetDlgItem(hDlg, TXT_MESSAGE), 
                  ws.left - icoWidth, ws.top, 
                  ws.right - ws.left + needX, ws.bottom - ws.top + needY,
                  FALSE);
            // resize whiterect control
            GetWindowRect(GetDlgItem(hDlg, STATIC_WHITERECT), &ws);
            OffsetRect(&ws, -mpt.x, -mpt.y);
            MoveWindow(GetDlgItem(hDlg, STATIC_WHITERECT), 
                  ws.left, ws.top, 
                  ws.right - ws.left + needX, ws.bottom - ws.top,
                  FALSE);
            // move icon control
            GetWindowRect(GetDlgItem(hDlg, ICO_DLGLOGO), &ws);
            OffsetRect(&ws, -mpt.x, -mpt.y);
            MoveWindow(GetDlgItem(hDlg, ICO_DLGLOGO), 
                  ws.left + needX, ws.top, 
                  ws.right - ws.left, ws.bottom - ws.top,
                  FALSE);
            // resize name text control
            GetWindowRect(GetDlgItem(hDlg, TXT_NAME), &ws);
            OffsetRect(&ws, -mpt.x, -mpt.y);
            MoveWindow(GetDlgItem(hDlg, TXT_NAME), 
                  ws.left, ws.top, 
                  ws.right - ws.left + needX, ws.bottom - ws.top,
                  FALSE);
            // resize line 1 control
            GetWindowRect(GetDlgItem(hDlg, STATIC_LINE1), &ws);
            OffsetRect(&ws, -mpt.x, -mpt.y);
            MoveWindow(GetDlgItem(hDlg, STATIC_LINE1), 
                  ws.left, ws.top, 
                  ws.right - ws.left + needX, ws.bottom - ws.top,
                  FALSE);
            // resize line 2 control
            GetWindowRect(GetDlgItem(hDlg, STATIC_LINE2), &ws);
            OffsetRect(&ws, -mpt.x, -mpt.y);
            MoveWindow(GetDlgItem(hDlg, STATIC_LINE2), 
                  ws.left, ws.top + needY, 
                  ws.right - ws.left + needX, ws.bottom - ws.top,
                  FALSE);
            
            //
            // Do pushbutton positioning
            //
            {
               RECT rcOk, rcAll, rcNone, rcCancel;
               LONG okWidth, caWidth, allWidth, noneWidth, dlgMid;

               // get button rectangles
               GetWindowRect(GetDlgItem(hDlg, IDOK), &rcOk);
               OffsetRect(&rcOk, -mpt.x, -mpt.y + needY);
               
			   GetWindowRect(GetDlgItem(hDlg, IDALL), &rcAll);
               OffsetRect(&rcAll, -mpt.x, -mpt.y + needY);
               
			   GetWindowRect(GetDlgItem(hDlg, IDNONE), &rcNone);
               OffsetRect(&rcNone, -mpt.x, -mpt.y + needY);

			   GetWindowRect(GetDlgItem(hDlg, IDCANCEL), &rcCancel);
               OffsetRect(&rcCancel, -mpt.x, -mpt.y + needY);
               
			   okWidth = rcOk.right - rcOk.left;
               allWidth = rcAll.right - rcAll.left;
			   noneWidth = rcNone.right - rcNone.left;
               caWidth = rcCancel.right - rcCancel.left;
               dlgMid = (rcDlg.right - rcDlg.left) / 2;

               // load button configuration
               switch(pmb->uType & 0x0000000FL) {
               
                  case MB_YESALLNO:
                     retOk = IDYES;
                     retCancel = IDNO;
                     // set font captions
                     SetDlgItemText(hDlg, IDOK, _T("Yes"));
                     SetDlgItemText(hDlg, IDCANCEL, _T("No"));
                     
					 rcCancel.right = rcDlg.right - rcDlg.left - 10;
                     rcCancel.left = rcCancel.right - caWidth;
					 rcNone.right = rcCancel.left - 5; 
                     rcNone.left = rcNone.right - noneWidth;
                     rcAll.right = rcNone.left - 5;
					 rcAll.left = rcAll.right - allWidth;
					 rcOk.right = rcAll.left - 5;
					 rcOk.left = rcOk.right - okWidth;
                     // move all button
                     MoveWindow(GetDlgItem(hDlg, IDALL), 
                           rcAll.left, rcAll.top, 
                           rcAll.right - rcAll.left, rcAll.bottom - rcAll.top,
                           FALSE);
                     // move none button
                     MoveWindow(GetDlgItem(hDlg, IDNONE), 
                           rcNone.left, rcNone.top, 
                           rcNone.right - rcNone.left, rcNone.bottom - rcNone.top,
                           FALSE);
                     // show buttons
                     ShowWindow(GetDlgItem(hDlg, IDCANCEL), SW_SHOW);
                     ShowWindow(GetDlgItem(hDlg, IDALL), SW_SHOW);
                     ShowWindow(GetDlgItem(hDlg, IDNONE), SW_SHOW);
                     break;

                  case MB_YESNO:
                     retOk = IDYES;
                     retCancel = IDNO;
                     SetDlgItemText(hDlg, IDOK, _T("Yes"));
                     SetDlgItemText(hDlg, IDCANCEL, _T("No"));

                  case MB_OKCANCEL:
                     rcOk.left = dlgMid - okWidth - 10;
                     rcOk.right = rcOk.left + okWidth;
                     rcCancel.left = dlgMid + 10;
                     rcCancel.right = rcCancel.left + caWidth;
                     ShowWindow(GetDlgItem(hDlg, IDCANCEL), SW_SHOW);
                     break;

                  default:
                     rcOk.left = dlgMid - (okWidth / 2);
                     rcOk.right = rcOk.left + okWidth;
                     break;
               }
               // move ok button
               MoveWindow(GetDlgItem(hDlg, IDOK), 
                  rcOk.left, rcOk.top, 
                  rcOk.right - rcOk.left, rcOk.bottom - rcOk.top,
                  FALSE);
               // move cancel button
               MoveWindow(GetDlgItem(hDlg, IDCANCEL), 
                     rcCancel.left, rcCancel.top, 
                     rcCancel.right - rcCancel.left, rcCancel.bottom - rcCancel.top,
                     FALSE);
            }   
         }
         // set text's
         if((pmb->uType & 0xF0000000) == MB_UNICODE) {
            SetWindowTextW(hDlg, pmb->pwszTitle);
            SetDlgItemTextW(hDlg, TXT_NAME, pmb->pwszInfoText);
            SetDlgItemTextW(hDlg, TXT_MESSAGE, pmb->pwszMsg);
         }
         else {
            SetWindowTextA(hDlg, pmb->pszTitle);
            SetDlgItemTextA(hDlg, TXT_NAME, pmb->pszInfoText);
            SetDlgItemTextA(hDlg, TXT_MESSAGE, pmb->pszMsg);
         }
         TranslateDialogDefault(hDlg);
         return TRUE;
      }

      case WM_CTLCOLORSTATIC:
         if(GetDlgItem(hDlg, STATIC_WHITERECT) == (HWND)lParam || GetDlgItem(hDlg, ICO_DLGLOGO) == (HWND)lParam) {
            SetBkColor((HDC)wParam, RGB(255, 255, 255));
            return (BOOL)GetStockObject(WHITE_BRUSH);
         }
         else
         if(GetDlgItem(hDlg, ICO_MSGDLG) == (HWND)lParam) {
            SetBkColor((HDC)wParam, GetSysColor(COLOR_3DFACE));
            return (BOOL)GetSysColorBrush(COLOR_3DFACE);
         }
         SetBkMode((HDC)wParam, TRANSPARENT);
         return (BOOL)GetStockObject(NULL_BRUSH);

      case WM_COMMAND:
         switch(LOWORD(wParam)) {
            case IDOK:
               EndDialog(hDlg, retOk);
               break;
            case IDCANCEL:
               EndDialog(hDlg, retCancel);
               break;
            case IDALL:
               EndDialog(hDlg, retAll);
               break;
            case IDNONE:
               EndDialog(hDlg, IDNONE);
               break;
         }

      case WM_DESTROY:
         DeleteObject((HFONT)SendDlgItemMessage(hDlg, TXT_NAME, WM_GETFONT, 0, 0));
         break;
   }
   return FALSE;
}

/**
 * name:   MsgBoxService
 * desc:   is the service function for external plugins to use the nice messagebox 
 * param:   wParam   - hContact if valid
 *         lParam   - TMsgBox structure holding parameters
 **/
INT MsgBoxService(WPARAM wParam, LPARAM lParam)
{
   LPMSGBOX mBox = (LPMSGBOX)lParam;

   if(PtrIsValid(mBox) && mBox->uSize == sizeof(MSGBOX)) {
      if(mBox->hParent == NULL) {
         mBox->hParent = (HWND)CallService(MS_CLUI_GETHWND, 0, 0);
      }
      return DialogBoxParam(ghInst, MAKEINTRESOURCE(IDD_MSGBOX), mBox->hParent, (DLGPROC)MsgBoxProc, lParam);
   }
   return -1;
}

/**
 * name:   MsgBox
 * desc:   calls a messagebox 
 * param:   
 **/
INT CALLBACK MsgBoxA(HWND hParent, UINT uType, LPSTR pszTitle, LPSTR pszInfo, LPSTR pszFormat, ...)
{
	MSGBOX	mBox;
	CHAR	szMsg[MAX_PATH];
	LPSTR	pszMsg, pfmt;
	DWORD	dwMsg;
	va_list	vl;

	va_start(vl, pszFormat);

	pfmt = Translate(pszFormat);
	dwMsg = mir_vsnprintfA(szMsg, SIZEOF(szMsg), pfmt, vl);
	if(dwMsg >= SIZEOF(szMsg)) {
		pszMsg = (LPSTR)_alloca(dwMsg + 1);
		if(!pszMsg) return 1;
		mir_vsnprintfA(pszMsg, dwMsg + 1, pfmt, vl);
	}
	else
		pszMsg = szMsg;
    va_end(vl);
      
	mBox.uSize = sizeof(MSGBOX);
	mBox.hParent = hParent;
	mBox.hiLogo = LoadIcon(ghInst, MAKEINTRESOURCE(IDI_MAIN));
	mBox.hiMsg = NULL;
	mBox.pszTitle = pszTitle;
	mBox.pszInfoText = pszInfo;
	mBox.pszMsg = pszMsg;
	mBox.uType = uType;
	mBox.uType &= ~MB_UNICODE;
	return MsgBoxService(NULL, (LPARAM)&mBox);
}

/**
 * name:   MsgBox
 * desc:   calls a messagebox 
 * param:   
 **/
INT CALLBACK MsgBoxW(HWND hParent, UINT uType, LPWSTR pszTitle, LPWSTR pszInfo, LPWSTR pszFormat, ...)
{
	MSGBOX	mBox;
	WCHAR	szMsg[MAX_PATH];
	LPWSTR	pszMsg, pfmt;
	DWORD	dwMsg;
	va_list	vl;

	va_start(vl, pszFormat);

	pfmt = TranslateW(pszFormat);
	dwMsg = mir_vsnprintfW(szMsg, SIZEOF(szMsg), pfmt, vl);
	if(dwMsg >= SIZEOF(szMsg)) {
		pszMsg = (LPWSTR)_alloca((dwMsg + 1) * sizeof(WCHAR));
		if(!pszMsg) return 1;
		mir_vsnprintfW(pszMsg, dwMsg + 1, pfmt, vl);
	}
	else
		pszMsg = szMsg;
    va_end(vl);
      
	mBox.uSize = sizeof(MSGBOX);
	mBox.hParent = hParent;
	mBox.hiLogo = LoadIcon(ghInst, MAKEINTRESOURCE(IDI_MAIN));
	mBox.hiMsg = NULL;
	mBox.pwszTitle = pszTitle;
	mBox.pwszInfoText = pszInfo;
	mBox.pwszMsg = pszMsg;
	mBox.uType = uType;
	mBox.uType |= MB_UNICODE;
	return MsgBoxService(NULL, (LPARAM)&mBox);}

/**
 * name:   MsgErr
 * desc:   calls a messagebox 
 * param:   
 **/
INT CALLBACK MsgErr(HWND hParent, LPCTSTR pszFormat, ...)
{
	MSGBOX mBox;
	va_list	vl;
	TCHAR	szMsg[MAX_PATH];
	LPTSTR	pszMsg, pfmt;
	DWORD	dwMsg;

	va_start(vl, pszFormat);

	pfmt = TranslateTS(pszFormat);
	dwMsg = mir_vsntprintf(szMsg, SIZEOF(szMsg), pfmt, vl);
	if(dwMsg >= SIZEOF(szMsg)) {
		pszMsg = (LPTSTR)_alloca((dwMsg + 1) * sizeof(WCHAR));
		if(!pszMsg) return 1;
		mir_vsntprintf(pszMsg, dwMsg + 1, pfmt, vl);
	}
	else
		pszMsg = szMsg;
    va_end(vl);

	mBox.uSize = sizeof(MSGBOX);
	mBox.hParent = hParent;
	mBox.hiLogo = LoadIcon(ghInst, MAKEINTRESOURCE(IDI_MAIN));
	mBox.hiMsg = NULL;
	mBox.ptszTitle = _T("Error");
	mBox.ptszInfoText = _T("Error message from \"Extended UserInfo\"");
	mBox.ptszMsg = pszMsg;
	mBox.uType = MB_OK|MB_ICON_ERROR|MB_TCHAR;
	return MsgBoxService(NULL, (LPARAM)&mBox);
}

